package com.xuebusi.common.hotload;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

/**
 * 加载manager的工厂
 * Created by SYJ on 2017/11/14.
 */
public class ManagerFactory {
    //记录热加载的类的信息
    private static final Map<String, LoadInfo> loadTimeMap = new HashMap<>();
    //要加载的类的类路径
    public static final String CLASS_PATH = "E:/github-xuser/xuser/target/";
    //实现热加载的类的全名称(包名+类名)
    public static final String X_MANAGER = "com.xuebusi.common.hotload.XManager";

    public static BaseManager getManager(String className) {

        File loadFile = new File(CLASS_PATH + className.replaceAll("\\.", "/") + ".class");
        long lastModified = loadFile.lastModified();
        //如果未被加载
        if (loadTimeMap.get(className) == null) {
            //重新加载类
            load(className, lastModified);
        } else if (loadTimeMap.get(className).getLoadTime() != lastModified) {
            //如果加载类的时间戳变量,同样需要重新加载
            load(className, lastModified);
        }
        return loadTimeMap.get(className).getManager();
    }

    private static void load(String className, long lastModified) {
        XClassLoader loader = new XClassLoader(CLASS_PATH);
        Class<?> loadClass = null;
        try {
            loadClass = loader.loadClass(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        BaseManager manager = newInstance(loadClass);
        LoadInfo loadInfo = new LoadInfo(loader, lastModified);
        loadInfo.setManager(manager);
        loadTimeMap.put(className, loadInfo);
    }

    /**
     * 以反射的方式创建BaseManager的子类对象
     * @param loadClass
     * @return
     */
    private static BaseManager newInstance(Class<?> loadClass) {
        try {
            return (BaseManager) loadClass.getConstructor(new Class[]{}).newInstance(new Object[]{});
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }


}
